package com.qws.k9.flutter_k9

import android.content.Context
import android.os.Bundle
import android.os.RemoteException
import android.util.Log
import androidx.annotation.NonNull
import com.alibaba.fastjson.JSON
import com.pos.sdk.DeviceManager
import com.pos.sdk.DevicesFactory
import com.pos.sdk.callback.ResultCallback
import com.pos.sdk.printer.IPrinterResultListener
import com.pos.sdk.printer.PrinterDevice
import com.pos.sdk.printer.param.MultipleTextPrintItemParam
import com.pos.sdk.printer.param.PrintItemAlign
import com.pos.sdk.printer.param.TextPrintItemParam
import com.qws.k9.flutter_k9.bean.MultipleTextCommand
import com.qws.k9.flutter_k9.bean.TextCommand
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

/** FlutterK9Plugin */
class FlutterK9Plugin : FlutterPlugin, MethodCallHandler {

    /// The MethodChannel that will the communication between Flutter and native Android
    ///
    /// This local reference serves to register the plugin with the Flutter Engine and unregister it
    /// when the Flutter Engine is detached from the Activity
    private lateinit var channel: MethodChannel

    private lateinit var context: Context

    private lateinit var mPrinter: PrinterDevice

    override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        context = flutterPluginBinding.applicationContext
        channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_k9")
        channel.setMethodCallHandler(this)
    }

    override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
        if (call.method == "getPlatformVersion") {
            result.success("Android ${android.os.Build.VERSION.RELEASE}")
        } else if (call.method == "connect") {
            connect(result)
        } else if (call.method == "print") {
            if (call.arguments is Map<*, *>) {
                val data = call.arguments as Map<*, *>;
                val commands = data["commands"]
                printAsync(commands as MutableList<Map<String, Any>>);
            }
            result.success(true)
        } else {
            result.notImplemented()
        }
    }

    private fun printAsync(commands: MutableList<Map<String, Any>>) {
        commands.forEach { that ->
            if (that["type"] == 1) {
                val textCommand = JSON.parseObject(JSON.toJSONString(that), TextCommand::class.java)
                val item = toTextParam(textCommand)
                mPrinter.addTextPrintItem(item)
                textCommand.lineSpace?.let {
                    mPrinter.addTextPrintItem(addLines(it))
                }
            } else if (that["type"] == 2) {
                val multipleText = JSON.parseObject(JSON.toJSONString(that), MultipleTextCommand::class.java)
                val items: MutableList<TextPrintItemParam> = arrayListOf()
                multipleText.texts.forEach {
                    items.add(toTextParam(it))
                }
                mPrinter.addMultipleTextPrintItem(MultipleTextPrintItemParam(multipleText.scales.toFloatArray(), items.toTypedArray()))

                multipleText.lineSpace?.let {
                    mPrinter.addTextPrintItem(addLines(it))
                }
            }
        }

        val bundle = Bundle()
        mPrinter.print(bundle, object : IPrinterResultListener.Stub() {
            @Throws(RemoteException::class)
            override fun onPrintFinish() {
            }

            @Throws(RemoteException::class)
            override fun onPrintError(errorCode: Int, msg: String?) {
            }
        })
    }

    private fun toTextParam(textCommand: TextCommand) : TextPrintItemParam{
        val textItem = TextPrintItemParam()
        textItem.content = textCommand.content
        textCommand.bold?.let {
            textItem.isBold = it
        }
        textCommand.textSize?.let {
            textItem.textSize = it
        }
        textCommand.scaleWidth?.let {
            textItem.scaleWidth = it
        }
        textCommand.scaleHeight?.let {
            textItem.scaleHeight = it
        }
        textCommand.itemAlign?.let {
            textItem.itemAlign = PrintItemAlign.values()[it]
        }
        return textItem
    }

    private fun addLines(lines: Int): TextPrintItemParam {
        val sb = StringBuffer()
        val t1 = TextPrintItemParam()
        for (i in 0 until lines) {
            sb.append("\n")
        }
        t1.content = sb.toString()
        return t1
    }

    private fun connect(result: Result) {
        DevicesFactory.create(
            context,
            object : ResultCallback<DeviceManager> {
                override fun onFinish(deviceManager: DeviceManager) {
                    mPrinter = deviceManager.printDevice
                    result.success(true)
                }

                override fun onError(i: Int, s: String) {
                    Log.d("FlutterK9Plugin", "onError: $i,$s")
                    result.success(false)
                }
            })
    }
    override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
        channel.setMethodCallHandler(null)
    }
}
